type
Post
status
Published
date
Jun 29, 2022
slug
[NPUCTF2020]Mersenne-twister
summary
[NPUCTF2020]Mersenne-twister
tags
Crypto
CTF
category
CRYPTO
icon
password
[NPUCTF2020]Mersenne twister
from hashlib import * from itertools import * from binascii import hexlify , unhexlify from flag import flag ,seed assert len(flag) == 26 assert flag[:7] == 'npuctf{' assert flag[-1] == '}' XOR = lambda s1 ,s2 : bytes([x1 ^ x2 for x1 ,x2 in zip(s1 , s2)]) class mt73991: def __init__(self , seed): self.state = [seed] + [0] * 232 self.flag = 0 self.srand() self.generate() def srand(self): for i in range(232): self.state[i+1] = 1812433253 * (self.state[i] ^ (self.state[i] >> 27)) - i self.state[i+1] &= 0xffffffff def generate(self): for i in range(233): y = (self.state[i] & 0x80000000) | (self.state[(i+1)%233] & 0x7fffffff) temp = y >> 1 temp ^= self.state[(i + 130) % 233] if y & 1: temp ^= 0x9908f23f self.state[i] = temp def getramdanbits(self): if self.flag == 233: self.generate() self.flag = 0 bits = self.Next(self.state[self.flag]).to_bytes(4 , 'big') self.flag += 1 return bits def Next(self , tmp): tmp ^= (tmp >> 11) tmp ^= (tmp << 7) & 0x9ddf4680 tmp ^= (tmp << 15) & 0xefc65400 tmp ^= (tmp >> 18) & 0x34adf670 return tmp def encrypt(key , plain): tmp = md5(plain).digest() return hexlify(XOR(tmp , key)) if __name__ == "__main__": flag = flag.encode() random = mt73991(seed) f = open('./cipher.txt' , 'wb') for i in flag: key = b''.join([random.getramdanbits() for _ in range(4)]) cipher = encrypt(key , chr(i).encode()) f.write(cipher) #cef4876036ee8b55aa59bca043725bf350a5e491debdef7ef7d63e9609a288ca1e2c82a7fe566bd8709e73c8d495ea504a486ed11189faf8e6fb35617e47d2d1ad5e4783e96afeaae9f7104ec477fb39fe4ec619bf58289709e15c4449f03fc51cba918cd0ebfdc12376b41e7815406482733b3b200826b6c78d86563edaea94dccf459a4291517a4b8367d7b4a53aeecd7e0accf661bfc726f5ba62e1c0e04100108ad32e7d5711f780185cba5cf31d328bee84066be4ab9582cf9d4bfe3c6f96a7732e1c37d800c90fd46277147f0a26c149dcd5eeb0f2df0c075627bc220be5eefdd67186056ac28c21e155a7f247664aaecdb498134de274df10114d1f06f84dd21820f150d69c9439d909dec0f5ccfeab61b62db2ea91d31bc8163ff16c7f458006bd5ac4a5f5bfae2770b23ccfb7195b76aa0a9aa146831667a7b9fe08c19e691afadccb3ca5169ef3fabaa3dad47d536e89ed4cee6f788bc969c3ad3137850ebfc46a73af2b0c036c3da4b4a16506f499445c604dd73eeb846a52f881515a3ad0ab448b4f9ed3e0ab1fffac60b223dde6450ba6198e90e14de107aaf2
MT19937类型的
我们可以知道flag以’npuctf’开头
那么可以求出前几个随机数
这道题需要求的是seed
那么只要知道第一个随机数就可以
然后可以逆一下next()
之前存的脚本
import string from binascii import hexlify from hashlib import md5 from Crypto.Util.number import * # right shift inverse def inverse_right(res, shift, bits=32): tmp = res for i in range(bits // shift): tmp = res ^ tmp >> shift return tmp # right shift with mask inverse def inverse_right_mask(res, shift, mask, bits=32): tmp = res for i in range(bits // shift): tmp = res ^ tmp >> shift & mask return tmp # left shift inverse def inverse_left(res, shift, bits=32): tmp = res for i in range(bits // shift): tmp = res ^ tmp << shift return tmp # left shift with mask inverse def inverse_left_mask(res, shift, mask, bits=32): tmp = res for i in range(bits // shift): tmp = res ^ tmp << shift & mask return tmp def extract_number(tmp): tmp ^= (tmp >> 11) tmp ^= (tmp << 7) & 0x9ddf4680 tmp ^= (tmp << 15) & 0xefc65400 tmp ^= (tmp >> 18) & 0x34adf670 return tmp def recover(y): y = inverse_right_mask(y,18,0x34adf670) y = inverse_left_mask(y,15,0xefc65400) y = inverse_left_mask(y,7,0x9ddf4680) y = inverse_right(y,11) return y c='cef4876036ee8b55aa59bca043725bf350a5e491debdef7ef7d63e9609a288ca1e2c82a7fe566bd8709e73c8d495ea504a486ed11189faf8e6fb35617e47d2d1ad5e4783e96afeaae9f7104ec477fb39fe4ec619bf58289709e15c4449f03fc51cba918cd0ebfdc12376b41e7815406482733b3b200826b6c78d86563edaea94dccf459a4291517a4b8367d7b4a53aeecd7e0accf661bfc726f5ba62e1c0e04100108ad32e7d5711f780185cba5cf31d328bee84066be4ab9582cf9d4bfe3c6f96a7732e1c37d800c90fd46277147f0a26c149dcd5eeb0f2df0c075627bc220be5eefdd67186056ac28c21e155a7f247664aaecdb498134de274df10114d1f06f84dd21820f150d69c9439d909dec0f5ccfeab61b62db2ea91d31bc8163ff16c7f458006bd5ac4a5f5bfae2770b23ccfb7195b76aa0a9aa146831667a7b9fe08c19e691afadccb3ca5169ef3fabaa3dad47d536e89ed4cee6f788bc969c3ad3137850ebfc46a73af2b0c036c3da4b4a16506f499445c604dd73eeb846a52f881515a3ad0ab448b4f9ed3e0ab1fffac60b223dde6450ba6198e90e14de107aaf2' p='n'.encode() tmp=md5(p).hexdigest() XOR = lambda s1 ,s2 : bytes([x1 ^ x2 for x1 ,x2 in zip(s1 , s2)]) m1=eval('0x'+tmp[:8])^eval('0x'+c[:8]) key=recover(m1) print(key)
然后再求seed
更新一下
知道flag最后一位‘}’ 就知道state[103] 可以求出state[104]
就可以逆回去
from gmpy2 import invert def backtrace(cur): high = 0x80000000 low = 0x7fffffff mask = 0x9908f23f state = cur tmp = state[1]^state[0] if tmp & high == high: tmp ^= mask tmp <<= 1 tmp |= 1 else: tmp <<=1 # recover highest bit state= tmp & low return state def invert_right(res,shift): tmp = res for i in range(32//shift): res = tmp^res>>shift return res&0xFFFFFFFF def recover(last): n = 1<<32 inv = invert(1812433253,n) for i in range(104,0,-1): last = ((last+i-1)*inv)%n last = invert_right(last,27) return last s=[778501557,1167644902] s228=backtrace(s) print(bin(s228)) seed=(recover(s228)) print(seed)
得到seed 直接可以求解
seed=1668245885 class mt73991: def __init__(self, seed): self.state = [seed] + [0] * 232 self.flag = 0 self.srand() self.generate() def srand(self): for i in range(232): self.state[i + 1] = 1812433253 * (self.state[i] ^ (self.state[i] >> 27)) - i self.state[i + 1] &= 0xffffffff def generate(self): for i in range(233): y = (self.state[i] & 0x80000000) | (self.state[(i + 1) % 233] & 0x7fffffff) temp = y >> 1 temp ^= self.state[(i + 130) % 233] if y & 1: temp ^= 0x9908f23f self.state[i] = temp def getramdanbits(self): if self.flag == 233: self.generate() self.flag = 0 bits = self.Next(self.state[self.flag]).to_bytes(4, 'big') self.flag += 1 return bits def Next(self, tmp): tmp ^= (tmp >> 11) tmp ^= (tmp << 7) & 0x9ddf4680 tmp ^= (tmp << 15) & 0xefc65400 tmp ^= (tmp >> 18) & 0x34adf670 return tmp c='cef4876036ee8b55aa59bca043725bf350a5e491debdef7ef7d63e9609a288ca1e2c82a7fe566bd8709e73c8d495ea504a486ed11189faf8e6fb35617e47d2d1ad5e4783e96afeaae9f7104ec477fb39fe4ec619bf58289709e15c4449f03fc51cba918cd0ebfdc12376b41e7815406482733b3b200826b6c78d86563edaea94dccf459a4291517a4b8367d7b4a53aeecd7e0accf661bfc726f5ba62e1c0e04100108ad32e7d5711f780185cba5cf31d328bee84066be4ab9582cf9d4bfe3c6f96a7732e1c37d800c90fd46277147f0a26c149dcd5eeb0f2df0c075627bc220be5eefdd67186056ac28c21e155a7f247664aaecdb498134de274df10114d1f06f84dd21820f150d69c9439d909dec0f5ccfeab61b62db2ea91d31bc8163ff16c7f458006bd5ac4a5f5bfae2770b23ccfb7195b76aa0a9aa146831667a7b9fe08c19e691afadccb3ca5169ef3fabaa3dad47d536e89ed4cee6f788bc969c3ad3137850ebfc46a73af2b0c036c3da4b4a16506f499445c604dd73eeb846a52f881515a3ad0ab448b4f9ed3e0ab1fffac60b223dde6450ba6198e90e14de107aaf2' table=string.printable random=mt73991(seed) for i in range(0,len(c),32): tmp=c[i:i+32] key=b''.join([random.getramdanbits() for _ in range(4)]) key=bytes_to_long(key) md=hex(eval('0x'+tmp)^key)[2:].zfill(32) for j in table: if(md5(j.encode()).hexdigest()==md): print(j,end='') break
主要是字节,hex,字符串转换有点混乱。。
- 作者:Putao0v0
- 链接:https://tangly1024.com/article/%5BNPUCTF2020%5DMersenne-twister
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章